﻿using LightCAD.Core;
using LightCAD.Drawing;
using LightCAD.Runtime;
using LightCAD.UI.Controls;
using LightCAD.UI.LineType;
using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;

namespace LightCAD.UI
{
    public partial class DrawingEditWindow : DockContent, IDrawingEditControl
    {
        public string Guid { get; } = System.Guid.NewGuid().ToString();
        public static int HoverDelayTime = 500;//悬停延迟时间，毫秒
        public IDocumentEditor Editor => this.DrawingEditRt;
        internal DocumentRuntime docRt;
        internal event Action<string, MouseEventRuntime> mouseEvent;
        internal event Action<KeyEventRuntime> keyDown;
        internal event Action<KeyEventRuntime> keyUp;
        internal event Action<Bounds> sizeChanged;
        internal event Action<SKSurface> skRender;
        internal event EventHandler mouseDown;

        MainUIWindow mainUI;

        private MouseEventArgs movedEvent;
        private bool isPointerHovering;
        private Point preHoverLocation;
        private System.Timers.Timer hoverTimer;
        private System.Windows.Forms.Timer tmRender;

        private TextBox tbInfo;
        private Label lblInfo;

        private bool inRender;
        private bool isActive;

        private LcDocument document;
        private LcLayout layout;
        private LcViewport viewport;
        private static LayerDropDown layerDropDown;
        private static ColorDropDown colorDropDown;
        private static LineTypeDropDown linetypeDropDown;
        private static LineWidthDropDown linewidthDropDown;
        private static TransprenceDropDown transparenceDropDown;

        public DrawingEditWindow(DocumentRuntime docRt)
        {

            // 添加一个输入框，用于输入长度
            tbInfo = new TextBox();
            tbInfo.Visible = false;
            tbInfo.KeyDown += TbInfo_KeyDown;

            lblInfo = new Label();
            lblInfo.AutoSize = true;
            lblInfo.Location = new Point(1, 1);
            lblInfo.Name = "lblInfo";
            lblInfo.Size = new Size(0, 20);
            InitializeComponent();
            this.pnlDrawingEditor.Controls.Add(tbInfo);
            tbInfo.BringToFront();
            this.pnlDrawingEditor.Controls.Add(lblInfo);
            lblInfo.BringToFront();


            tmRender = new System.Windows.Forms.Timer(components);
            tmRender.Interval = 16;
            tmRender.Tick += timer1_Tick;
            this.tmRender.Enabled = true;

            #region SKGLControl
            this.skglControl1.KeyPress += SkglControl_KeyPress;
            this.skglControl1.MouseDown += SkglControl_MouseDown;
            this.skglControl1.MouseMove += SkglControl_MouseMove;
            this.skglControl1.MouseUp += SkglControl_MouseUp;
            this.skglControl1.MouseWheel += SkglControl_MouseWheel;
            this.skglControl1.KeyDown += SkglControl_KeyDown;
            this.skglControl1.KeyUp += SkglControl1_KeyUp;
            this.skglControl1.SizeChanged += SkglControl1_SizeChanged;
            this.skglControl1.PaintSurface += SkglControl1_PaintSurface;
            #endregion

            this.hoverTimer = new System.Timers.Timer();
            this.hoverTimer.Interval = HoverDelayTime;
            this.hoverTimer.Elapsed += HoverTimer_Elapsed;

            this.contextMenu.ItemClicked += ContextMenu_ItemClicked;

            this.AutoScaleMode = AutoScaleMode.None;
            this.Load += MainView_Load;

            this.docRt = docRt;
            docRt.Action.SelectsChanged += Action_SelectsChanged;
            this.Enter += DrawingEditWindow_Enter;
        }

        private void DrawingEditWindow_Enter(object? sender, EventArgs e)
        {
            if (this.Visible)
                this.SetActive(true);
        }

        private void Action_SelectsChanged(IDocumentEditor sender, SelectedEventArgs args)
        {
            layerDropDown.ResetSelectLayer(args);
            colorDropDown.ResetSelectColor(args);
            linetypeDropDown.ResetSelectLineType(args);
            linewidthDropDown.ResetSelectLineWidth(args);
        }

        public void SetLayOut(LcDocument document, LcLayout layOut)
        {
            this.document = document;
            this.layout = layOut;
            this.viewport = this.layout.Viewports[0];
            this.DrawingEditRt = new DrawingEditRuntime(docRt, this, this.CommandBar);
        }
        public void SetLocation(string point)
        {
            toolStripStatusLabel1.Text = point;
        }
        private void MainView_Load(object? sender, EventArgs e)
        {
            this.mainUI = UIUtils.GetParent<MainUIWindow>(this);
            this.mainUI.ActiveChanged += MainUI_ActiveChanged;
            CommandCenter.Initilize();
            this.sizeChanged?.Invoke(this.skglControl1.Bounds.ToRuntime());
            layerDropDown = new LayerDropDown(this.document);

            layerDropDown.AnchorSize = new Size(306, 24);
            layerDropDown.BackColor = Color.White;
            layerDropDown.DockSide = DropDownControl.eDockSide.Right;
            layerDropDown.ForeColor = Color.Black;
            layerDropDown.Location = new Point(0, 0);
            layerDropDown.Margin = new Padding(3, 4, 3, 4);
            layerDropDown.Name = "layerDropDown1";
            layerDropDown.Size = new Size(336, 24);
            layerDropDown.TabIndex = 1;
            this.Controls.Add(layerDropDown);
            layerDropDown.BringToFront();
            LayerManageWindow.LayerChanged += LayerManageWindow_LayerChanged;

            colorDropDown = new ColorDropDown(this.document);
            colorDropDown.AnchorSize = new Size(210, 24);
            colorDropDown.BackColor = Color.White;
            colorDropDown.DockSide = DropDownControl.eDockSide.Right;
            colorDropDown.ForeColor = Color.Black;
            colorDropDown.Location = new Point(338, 0);
            colorDropDown.Margin = new Padding(3, 4, 3, 4);
            colorDropDown.Name = "colorDropDown1";
            colorDropDown.Size = new Size(210, 24);
            colorDropDown.TabIndex = 1;
            this.Controls.Add(colorDropDown);
            colorDropDown.BringToFront();

            linetypeDropDown = new LineTypeDropDown(this.document);
            linetypeDropDown.AnchorSize = new Size(210, 24);
            linetypeDropDown.BackColor = Color.White;
            linetypeDropDown.DockSide = DropDownControl.eDockSide.Right;
            linetypeDropDown.ForeColor = Color.Black;
            linetypeDropDown.Location = new Point(550, 0);
            linetypeDropDown.Margin = new Padding(3, 4, 3, 4);
            linetypeDropDown.Name = "linetypeDropDown";
            linetypeDropDown.Size = new Size(210, 24);
            linetypeDropDown.TabIndex = 1;
            this.Controls.Add(linetypeDropDown);
            linetypeDropDown.BringToFront();
            LcLineTypeCollection.LineTypeChanged += LineTypeManageWindow_LineTypeChanged;

            linewidthDropDown = new LineWidthDropDown(this.document);
            linewidthDropDown.AnchorSize = new Size(210, 24);
            linewidthDropDown.BackColor = Color.White;
            linewidthDropDown.DockSide = DropDownControl.eDockSide.Right;
            linewidthDropDown.ForeColor = Color.Black;
            linewidthDropDown.Location = new Point(762, 0);
            linewidthDropDown.Margin = new Padding(3, 4, 3, 4);
            linewidthDropDown.Name = "linewidthDropDown";
            linewidthDropDown.Size = new Size(210, 24);
            linewidthDropDown.TabIndex = 1;
            this.Controls.Add(linewidthDropDown);
            linewidthDropDown.BringToFront();

            transparenceDropDown = new TransprenceDropDown();
            transparenceDropDown.AnchorSize = new Size(320, 24);
            transparenceDropDown.BackColor = Color.White;
            transparenceDropDown.DockSide = DropDownControl.eDockSide.Left;
            transparenceDropDown.ForeColor = Color.Black;
            transparenceDropDown.Location = new Point(974, 0);
            transparenceDropDown.Margin = new Padding(3, 4, 3, 4);
            transparenceDropDown.Name = "transparenceDropDown";
            transparenceDropDown.Size = new Size(320, 24);
            transparenceDropDown.TabIndex = 1;
            this.Controls.Add(transparenceDropDown);
            transparenceDropDown.BringToFront();
        }

        private void LayerManageWindow_LayerChanged(object? sender, LcDocument e)
        {
            layerDropDown.InitLayers(this.document);
            colorDropDown.InitColors(this.document);
        }

        private void LineTypeManageWindow_LineTypeChanged(object? sender, EventArgs e)
        {
            linetypeDropDown.InitLineType(this.document);
        }

        public static void RefreshLayer(LcDocument document)
        {
            layerDropDown.InitLayers(document);
        }

        public static void RefreshLineType(LcDocument document)
        {
            linetypeDropDown.InitLineType(document);
        }
        private void MainUI_ActiveChanged(object? sender, ActiveChangedEventArgs e)
        {
            if (e.IsActive)
            {
                //CommandCenter.Instance.BindControl(this.CommandBar);
            }
            Debug.Print("DocumentControl IsActive: " + e.IsActive.ToString());
        }


        public EditorType EditorType => EditorType.Drawing;
        public DrawingEditRuntime DrawingEditRt { get; private set; }
        public CommandCenter CommandCenter => DrawingEditRt.CommandCenter;


        private void MainMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {

        }

        private void Menu_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            UIUtils.ExecuteCommand(e.ClickedItem.Name);
        }

        private void toolStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            UIUtils.ExecuteCommand(e.ClickedItem.Name);
        }




        private void HoverTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            hoverTimer.Stop();
            this.isPointerHovering = true;
            HoverEventStart();
        }
        private void HoverEventStart()
        {
            preHoverLocation = this.movedEvent.Location;
            mouseEvent?.Invoke("HoverStart", this.movedEvent.ToRuntime());
        }
        private void HoverEventEnd()
        {
            mouseEvent?.Invoke("HoverEnd", this.movedEvent.ToRuntime());
        }
        public void ShowHoverTip(object content)
        {

        }

        private void TbInfo_KeyDown(object? sender, KeyEventArgs e)
        {
            switch (e.KeyValue)
            {
                case 27:
                    skglControl1.Focus();
                    tbInfo.Text = string.Empty;
                    break;
                case 13:
                case 32:
                    skglControl1.Focus();
                    SendKeys.Send("{ENTER}");
                    break;
            }
        }
        public string GetInputText()
        {
            return tbInfo.Text;
        }
        public void HideInputText()
        {
            tbInfo.Visible = false;
        }
        public void ShowInputText()
        {
            tbInfo.Visible = true;

        }
        public void SetInputText(string str)
        {
            tbInfo.Text = str;
        }


        private void timer1_Tick(object sender, EventArgs e)
        {
            if (inRender) return;
            this.skglControl1.Invalidate();
        }

        private void SkglControl1_PaintSurface(object? sender, SkiaSharp.Views.Desktop.SKPaintGLSurfaceEventArgs e)
        {
            inRender = true;
            try
            {
                skRender?.Invoke(e.Surface);
            }
            finally
            {
                inRender = false;
            }
        }
        private void SkglControl_KeyPress(object? sender, KeyPressEventArgs e)
        {
            // cad 可以输入字符串，不知道有什么用
            if (char.IsLetterOrDigit(e.KeyChar))
            {
                tbInfo.Text += e.KeyChar;
            }
            tbInfo.Focus();
            tbInfo.SelectionStart = tbInfo.Text.Length;
            tbInfo.SelectionLength = 0;
        }
        private void SkglControl_MouseDown(object? sender, MouseEventArgs e)
        {
            mouseDown?.Invoke(this, e);
            mouseEvent?.Invoke("Down", e.ToRuntime());
        }
        private void SkglControl_MouseMove(object? sender, MouseEventArgs e)
        {
            tbInfo.Location = new Point(e.Location.X + 10, e.Location.Y + 10);

            this.movedEvent = e;

            if (this.mainUI != null && this.mainUI.IsActive)
            {
                skglControl1.Focus();
            }

            //模拟处理悬停事件，停在某点一段时间触发事件，移动光标悬停结束，等待下一次悬停事件
            //需要位置发生改变才停止Hover事件，因为ToolTip的显示，会导致Move事件的重复触发
            if (this.isPointerHovering && preHoverLocation != e.Location)
            {
                this.isPointerHovering = false;
                HoverEventEnd();
            }
            hoverTimer.Stop();
            hoverTimer.Start();

            mouseEvent?.Invoke("Move", e.ToRuntime());
        }
        private void SkglControl_MouseUp(object? sender, MouseEventArgs e)
        {
            mouseEvent?.Invoke("Up", e.ToRuntime());
        }
        private void SkglControl_MouseWheel(object? sender, MouseEventArgs e)
        {
            mouseEvent?.Invoke("Wheel", e.ToRuntime());
        }
        private void SkglControl_KeyDown(object? sender, KeyEventArgs e)
        {
            keyDown?.Invoke(e.ToRuntime());
        }
        private void SkglControl1_KeyUp(object? sender, KeyEventArgs e)
        {
            keyUp?.Invoke(e.ToRuntime());
        }
        private void SkglControl1_SizeChanged(object? sender, EventArgs e)
        {
            // this.skglControl1.Visible = false;
            this.skglControl1.Enabled = true;
            sizeChanged?.Invoke(this.skglControl1.Bounds.ToRuntime());
            ///sizeChanged?.Invoke(this.skglControl1.Bounds.ToRuntime());
          //  // this.skglControl1.Invalidate();
            // this.skglControl1.Visible = true;
        }

        public void ShowInfo(string type, object info)
        {
            lblInfo.Text = info?.ToString();
        }
        public IPopupObject GetPopupObject(string type)
        {

            if (type == "ElementHover")
            {
                if (!this.components.Components.OfType<IPopupObject>().Any())
                {
                    this.components.Add(PopupInfo.Instance);
                }
                return PopupInfo.Instance;
            }
            return null;
        }

        public SKPoint PointToScreen(SKPoint point)
        {
            return this.PointToScreen(new Point((int)point.X, (int)point.Y)).ToSKPoint();
        }
        private Action closedAction;
        public void PopupContextMenu(Action closedAction)
        {
            this.closedAction = closedAction;
            this.contextMenu.Show(Control.MousePosition.X, Control.MousePosition.Y);
            this.contextMenu.Closed += ContextMenu_Closed;
        }

        private void ContextMenu_Closed(object? sender, ToolStripDropDownClosedEventArgs e)
        {
            this.contextMenu.Closed -= ContextMenu_Closed;
            closedAction?.Invoke();
        }
        private async void ContextMenu_ItemClicked(object? sender, ToolStripItemClickedEventArgs e)
        {
            var reault = await Task<CommandResult>.Run(() =>
            {
                //这里存在非常迷惑的问题，Task虽然是异步，但有可能执行很快，效果上类似同步执行，只有延迟一段时间，才能保证关闭事件里的代码优先执行
                Thread.Sleep(10);
                return CommandCenter.Execute("");
            });
            //Do something
        }

        public bool IsActive
        {
            get
            {
                return isActive;
            }

            internal set
            {
                isActive = value;
                this.tmRender.Enabled = value && this.isActive;
            }
        }
        public bool HoverEnabled { get; set; } = true;
        public bool ForceRefresh { get; set; }
        public long ViewportId => this.viewport.Id;

        public LcViewport ViewPort => this.viewport;



        public void AttachEvents(
            Action<string, MouseEventRuntime> mouseEvent,
            Action<KeyEventRuntime> keyDown,
            Action<KeyEventRuntime> keyUp,
            Action<Bounds> sizeChanged,
            Action<SKSurface> skRender)
        {
            if (mouseEvent != null) this.mouseEvent += mouseEvent;
            if (keyDown != null) this.keyDown += keyDown;
            if (keyUp != null) this.keyUp += keyUp;
            if (sizeChanged != null) this.sizeChanged += sizeChanged;
            if (skRender != null) this.skRender += skRender;
        }

        public void DetachEvents(
            Action<string, MouseEventRuntime> mouseEvent,
            Action<KeyEventRuntime> keyDown,
             Action<KeyEventRuntime> keyUp,
           Action<Bounds> sizeChanged,
            Action<SKSurface> skRender)
        {
            if (mouseEvent != null) this.mouseEvent -= mouseEvent;
            if (keyDown != null) this.keyDown -= keyDown;
            if (keyUp != null) this.keyUp -= keyDown;
            if (sizeChanged != null) this.sizeChanged -= sizeChanged;
            if (skRender != null) this.skRender -= skRender;
        }

        /// <summary>
        /// 触发刷新视口
        /// </summary>
        /// <param name="vportIds">如果为空，刷新所有视口</param>
        public void RefreshViewport()
        {
            this.ForceRefresh = true;
            this.skglControl1.Invalidate();
        }
        public void SetActive(bool isActive)
        {
            if (isActive)
            {
                this.BringToFront();
                this.Enabled = true;
                this.IsActive = true;
                this.DockPanel.Panes[1].ActiveContent = this;
                this.CommandCenter.SetActive();
            }
            else
            {
                this.IsActive = false;
                this.SendToBack();
                this.Enabled = false;
                RefreshViewport();//强制刷新不活动的视口，将光标等隐藏
            }
        }

    }
}
